#pragma once
#include "DXContext.h"
#include "DPI.h"

namespace DXBase
{
	namespace D3D
	{
		ref class Texture2D;
	}

	[Windows::Foundation::Metadata::WebHostHidden]
	public ref class DXTargetSwapPanelOrWindow sealed : IRenderTarget
	{
	public:
		DXTargetSwapPanelOrWindow();
		DXTargetSwapPanelOrWindow(Windows::UI::Xaml::Controls::SwapChainBackgroundPanel^ panel);
		property Windows::UI::Xaml::Controls::SwapChainBackgroundPanel^ Panel { Windows::UI::Xaml::Controls::SwapChainBackgroundPanel^ get() { return panel; } }

		virtual property Windows::Graphics::Display::DisplayOrientations Orientation { Windows::Graphics::Display::DisplayOrientations get() { return Windows::Graphics::Display::DisplayProperties::CurrentOrientation; } }
		virtual property float Dpi 
		{
			float get() { return dpi; } 
			void set(float value) 
			{
				if (value < DPI::MinDPI)
					throw ref new Platform::InvalidArgumentException();
				dpi = value; 
			}
		}
		virtual property USize PixelSize { USize get(); }

		virtual D3D::Texture2D^ Snapshot();

	internal:
		void ValidateTarget();
		virtual void RenderFinished() = IRenderTarget::EndRender;
		virtual void ClearDXData() = IContextBound::ClearDXData 
		{
			ntarget = nullptr; 
			swapChain = nullptr;
		}
		virtual property DXContext^ Context
		{
			DXContext^ get() = IContextBound::Context::get { return watcher.Context; } 
			void set(DXContext^ ctxt) = IContextBound::Context::set;
		}
		virtual NativeRenderTarget^ GetNativeTarget() = IRenderTarget::GetNativeTarget
		{
			ValidateTarget();
			LoadDXData();
			return ntarget;
		}
		virtual void LoadDXData() = IContextBound::LoadDXData;
		virtual property USize ViewportOffset { USize get() = IRenderTarget::ViewportOffset::get { return makeUSize(0, 0); } }

	private:
		float dpi;
		ContextWatcher watcher;
		Windows::UI::Xaml::Controls::SwapChainBackgroundPanel^ panel;
		void Init(Windows::UI::Xaml::Controls::SwapChainBackgroundPanel^ panel);

		NativeRenderTarget^ ntarget;
		Microsoft::WRL::ComPtr<IDXGISwapChain1> swapChain; // link to the swap chain
	};

	[Windows::Foundation::Metadata::WebHostHidden]
	public ref class DXTargetImageSource sealed : IRenderTarget
	{
	public:
		DXTargetImageSource(int w, int h);
		[Windows::Foundation::Metadata::DefaultOverload]
		DXTargetImageSource(int w, int h, bool isOpaque);
		DXTargetImageSource(Windows::UI::Xaml::Media::Imaging::SurfaceImageSource^ image, int w, int h);

		property Windows::UI::Xaml::Media::Imaging::SurfaceImageSource^ ImageSource { Windows::UI::Xaml::Media::Imaging::SurfaceImageSource^ get() { return image; } }

		property Windows::Graphics::Display::DisplayOrientations Orientation;
		virtual property float Dpi 
		{
			float get() { return dpi; } 
			void set(float value) 
			{
				if (value < DPI::MinDPI)
					throw ref new Platform::InvalidArgumentException();
				dpi = value; 
			}
		}
		virtual property USize PixelSize { USize get() { return makeUSize(width, height); } }

		virtual D3D::Texture2D^ Snapshot();

	internal:
		virtual void RenderFinished() = IRenderTarget::EndRender;
		virtual void ClearDXData() = IContextBound::ClearDXData { ntarget = nullptr; }
		virtual property DXContext^ Context
		{
			DXContext^ get() = IContextBound::Context::get { return watcher.Context; } 
			void set(DXContext^ ctxt) = IContextBound::Context::set;
		}
		virtual NativeRenderTarget^ GetNativeTarget() = IRenderTarget::GetNativeTarget
		{
			LoadDXData();
			return ntarget;
		}
		virtual void LoadDXData() = IContextBound::LoadDXData;
		virtual property USize ViewportOffset { USize get() = IRenderTarget::ViewportOffset::get { return makeUSize(mvoffset.x, mvoffset.y); } }

	private:
		ContextWatcher watcher;
		virtual Windows::Graphics::Display::DisplayOrientations GetOrientation() = IRenderTarget::Orientation::get { return Orientation; }
		Windows::UI::Xaml::Media::Imaging::SurfaceImageSource^ image;
		Microsoft::WRL::ComPtr<ISurfaceImageSourceNative> sysimg;
		int width, height;
		float dpi;
		void Init(Windows::UI::Xaml::Media::Imaging::SurfaceImageSource^ image, int w, int h);

		NativeRenderTarget^ ntarget;
		POINT mvoffset;
	};
}